package com.expires.test;

import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TransferQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @program: SpringBootDemos
 * @description:
 * @author: Kangsen
 * @create: 2022-06-08 15:51
 **/

public class ThreadExpires {
    //jvm 方式实现交替打印
    private final static Object lock=new Object();
    //juc 的方式实现交替打印
    private final static ReentrantLock reentrantLock = new ReentrantLock();
    private final static Condition condition = reentrantLock.newCondition();

    private static char[] aA = new char[]{'A','B','C','D','E','F','G'};
    private static char[] aN = new char[]{'1','2','3','4','5','6','7'};

    static class ThreadA implements Runnable{
        char[] chars = new char[]{'A','B','C','D','E','F','G'};
        int index = 0;
        @Override
        public void run() {
            while(true){
                synchronized (lock){
                    try {
                        System.out.println(chars[index++]);
                        lock.notify();
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        System.out.println(Thread.currentThread().getName());
                        if(index >= chars.length){
                            lock.notify();//打印完notify
                            break;
                        }
                    }
                }
            }
        }
    }

    //打印字母
    static class ThreadWord implements Runnable{
        char[] chars = new char[]{'A','B','C','D','E','F','G'};
        int index = 0;

        @Override
        public void run() {
            while(true){
                try {
                    reentrantLock.lock();
                    System.out.println(chars[index++]);
                    condition.signalAll();
                    condition.await();
                    if(index >= chars.length){
                        break;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    reentrantLock.unlock();
                }
            }
        }
    }

    static class ThreadB implements Runnable{
        char[] chars = new char[]{'1','2','3','4','5','6','7'};
        int index = 0;
        @Override
        public void run() {
            while(true){
                synchronized (lock){
                    try {
                        System.out.println(chars[index++]);
                        lock.notify();
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        System.out.println(Thread.currentThread().getName());
                        if(index >= chars.length){
                            lock.notify();
                            break;
                        }
                    }
                }
            }
        }
    }

    //打印字母
    static class ThreadNumber implements Runnable{
        char[] chars = new char[]{'1','2','3','4','5','6','7'};
        int index = 0;
        @Override
        public void run() {
            while(true){
                reentrantLock.lock();
                try {
                    System.out.println(chars[index++]);
                    condition.signalAll();
                    condition.await();
                    if(index >= chars.length){
                        break;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        }
    }

    //使用JUC的信号量控制: 两个线程分别控制对方的信号量  只用一个信号量无法控制两个线程
    private final static Semaphore semaphore1 = new Semaphore(0);
    private final static Semaphore semaphore2 = new Semaphore(1);
    static class Thread1 implements Runnable{
        private int index = 0;
        @Override
        public void run() {
            while (true){
                try {
                    semaphore1.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(index >= aA.length){
                    semaphore2.release();
                    break;
                }
                System.out.println(aA[index++]);
                semaphore2.release();
            }
        }
    }

    static class Thread2 implements Runnable{
        private int index = 0;
        @Override
        public void run() {
            while (true){
                try {
                    semaphore2.acquire();
                    if(index >= aN.length){
                        semaphore1.release();
                        break;
                    }
                    System.out.println(aN[index++]);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                semaphore1.release();
            }
        }
    }

    public static void main(String[] args) {
        //交替打印A1B2C3D4E5F6G7
        /*new Thread(new ThreadA()).start();
        new Thread(new ThreadB()).start();*/

        //使用condition
        /*new Thread(new ThreadWord()).start();
        new Thread(new ThreadNumber()).start();*/

        /*Thread t1 = null;
        Thread t2 = null;*/

        /*t1 = new Thread(() -> {
            for (char c : aA) {
                System.out.println(c);
                LockSupport.unpark(t2);
                LockSupport.park();

            }
        });

        t2 = new Thread(() -> {
            for (char c : aN) {
                System.out.println(c);
                LockSupport.unpark(t1);
                LockSupport.park();

            }
        });*/

        /**
         * 使用互斥信号量
         */
        /*new Thread(new Thread1()).start();
        new Thread(new Thread2()).start();*/


        /**
         * condition控制
         */
        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();
        /*Lock lock = new ReentrantLock();
        Condition conditionT1 = lock.newCondition();
        Condition conditionT2 = lock.newCondition();
        CountDownLatch latch = new CountDownLatch(1);

        new Thread(()->{
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.lock();
            try{
                for (char c : aI) {
                    System.out.println(c);
                    conditionT2.signal();//叫醒第2个队列的线程
                    conditionT1.await();//自己去第1个队列里面休息
                }
                conditionT2.signal();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"t1").start();

        new Thread(()->{
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.lock();
            try{
                for (char c : aC) {
                    System.out.println(c);
                    conditionT1.signal();
                    conditionT2.await();
                }
                conditionT1.signal();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"t2").start();
        //门栓放下 两个线程开始执行
        latch.countDown();*/

        /**
         *  交换队列
         * 同步队列实现 : 这个队列中只允许存在有一个数据 未被消费前 生产者阻塞   未被生产前 消费者阻塞
         * queue.take() : 消费  和   queue.transfer() : 生产
         */
        TransferQueue queue = new LinkedTransferQueue();
        new Thread(()->{
            for (char c : aC) {
                try {
                    Object take = queue.take();//队列中没有就阻塞
                    System.out.println(take);
                    queue.transfer(c);//给队列中存进去一个数据
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t1").start();

        new Thread(()->{
            for (char c : aI) {
                try {
                    queue.transfer(c);//存数据到队列中 若还没有消费就阻塞
                    Object take = queue.take();
                    System.out.println(take);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t1").start();
    }
}
